#include "cheetah/graphics/shader_object.h"

#include <stdio.h>

#include "cheetah/core/error.h"
#include "cheetah/graphics/utils.h"

namespace cheetah {
namespace graphics {
using namespace core;
ShaderObject::ShaderObject(int shader_type, const char *source, int source_type)
    : is_compiled_(false), shader_id_(0) {
  if (NULL == source) {
    Error("ShaderObject::ShaderObject, source is NULL");
    return;
  }

  shader_id_ = glCreateShader(shader_type);
  if (0 == shader_id_) {
    CheckErrorsGL("ShaderObject::ShaderObject");
    return;	
  }

  GLint code_length = 0;
  if (kFileSource == source_type) {
    char *code = NULL;
    code_length = ReadSahderFile(source, &code);
    if (0 == code_length) return;
    glShaderSource(shader_id_, 1, const_cast<const GLchar**>(&code),
                   &code_length);
    delete[] code;
  } else {
    const char *code = source;
    code_length = strlen(code);
    glShaderSource(shader_id_, 1, const_cast<const GLchar**>(&code),
                   &code_length);
  }

  glCompileShader(shader_id_);
  CheckCompileLog();
}

ShaderObject::~ShaderObject(void) {
  if(shader_id_) glDeleteShader(shader_id_);
}

int ShaderObject::ReadSahderFile(const char *file, char** code) {
  if (file == NULL) return 0;

  FILE *fd = fopen(file, "rb");
  if (fd == NULL) {
    Error("'ShaderObject::ReadShaderFile', failed to open '%s'", file);
    return 0;
  }
  fseek(fd, 0, SEEK_END);
  int len = ftell(fd);
  rewind(fd);
  char *buf = NULL;
  if(len > 1) {
    buf = new char[len + 1];
    fread(buf, sizeof(char), len, fd);
    buf[len] = '\0';
  }else {
    len = 0;
  }
  *code = buf;
  fclose(fd);
  return len;
}

void ShaderObject::CheckCompileLog() {
  GLint status;
  glGetShaderiv(shader_id_, GL_COMPILE_STATUS, &status);
  if (GL_TRUE == status) is_compiled_ = true;

  if(!is_compiled_) PrintCompileLog();
}

void ShaderObject::PrintCompileLog() {
  GLint len = 0;	
  glGetShaderiv(shader_id_, GL_INFO_LOG_LENGTH , &len);
  if(len < 2) return;
  char *compile_log = new char[len + 1];
  glGetShaderInfoLog(shader_id_, len, &len, compile_log);
  Error("ShaderObject::PrintCompileLog, %s", compile_log);
  delete[] compile_log;
}

} // graphics
} // cheetah

